<?php
/**
 ***********************************************************************************************************************
 * 访问记录
 * @author llq
 ***********************************************************************************************************************
 */
namespace soa\access\model\redis;
use artisan\config;

/**
 * Class record
 * @package soa\access\model\redis
 */
class record
{
    /**
     * 按IP存储
     */
    const IP_PREFIX = 'access:record:ip:';

    /**
     * 按账号存储
     */
    const ACCOUNT_PREFIX = 'access:record:account:';

    /**
     * 所有时段指标
     * @var array
     */
    private $indexes = [
        // 一分钟
        'one_minute',
        // 五分钟
        'five_minute',
        // 十五分钟
        'fifteen_minute',
        // 一小时
        'one_hour',
        // 六小时
        'six_hour',
        // 十二小时
        'twelve_hour',
        // 一天
        'one_day',
    ];

    /**
     * 默认设置过期时间
     * @var bool
     */
    private $need_set_ip_expire = true;

    /**
     * 默认设置过期时间
     * @var bool
     */
    private $need_set_account_expire = true;

    /**
     * @var
     */
    private $account_record;

    /**
     * @var
     */
    private $ip_record;


    /**
     * @param $service
     * @param $ip
     * @return bool|int
     */
    public function refreshByIp($service, $ip)
    {
        if(empty($service) || !is_string($service) || empty($ip) || !is_string($ip)) {
            return false;
        }
        $key = self::IP_PREFIX . $service . ':' . $ip;
        $ret = $this->getRedis()->hMset($key, $this->ip_record);
        if($this->need_set_ip_expire) {
            // 次日零点过期
            $this->getRedis()->expireat($key, strtotime('+1 day', strtotime(date('Y-m-d'))));
        }
        return $ret;
    }

    /**
     * @param $service
     * @param $account
     * @return bool|int
     */
    public function refreshByAccount($service, $account)
    {
        if(empty($service) || !is_string($service) || empty($account) || !is_string($account)) {
            return false;
        }

        $key = self::ACCOUNT_PREFIX . $service . ':' . $account;
        $ret = $this->getRedis()->hMset($key, $this->account_record);
        if($this->need_set_account_expire) {
            // 次日零点过期
            $this->getRedis()->expireat($key, strtotime('+1 day', strtotime(date('Y-m-d'))));
        }

        return $ret;
    }


    /**
     * @param $record
     * @return mixed
     */
    private function organize($record)
    {
        $now = time();
        // one_minute
        if(empty($record['one_minute_ttl']) || $now - $record['one_minute_ttl'] > 60) {
            $record['one_minute'] = 1;
            $record['one_minute_ttl'] = $now;
        } else {
            $record['one_minute'] = 1 + intval($record['one_minute']);
        }

        // five_minute
        if(empty($record['five_minute_ttl']) || $now - $record['five_minute_ttl'] > 300) {
            $record['five_minute'] = 1;
            $record['five_minute_ttl'] = $now;
        } else {
            $record['five_minute'] = 1 + intval($record['five_minute']);
        }

        // fifteen_minute
        if(empty($record['fifteen_minute_ttl']) || $now - $record['fifteen_minute_ttl'] > 900) {
            $record['fifteen_minute'] = 1;
            $record['fifteen_minute_ttl'] = $now;
        } else {
            $record['fifteen_minute'] = 1 + intval($record['fifteen_minute']);
        }

        // one_hour
        if(empty($record['one_hour_ttl']) || $now - $record['one_hour_ttl'] > 3600) {
            $record['one_hour'] = 1;
            $record['one_hour_ttl'] = $now;
        } else {
            $record['one_hour'] = 1 + intval($record['one_hour']);
        }

        // six_hour
        if(empty($record['six_hour_ttl']) || $now - $record['six_hour_ttl'] > 21600) {
            $record['six_hour'] = 1;
            $record['six_hour_ttl'] = $now;
        } else {
            $record['six_hour'] = 1 + intval($record['six_hour']);
        }

        // twelve_hour
        if(empty($record['twelve_hour_ttl']) || $now - $record['twelve_hour_ttl'] > 43200) {
            $record['twelve_hour'] = 1;
            $record['twelve_hour_ttl'] = $now;
        } else {
            $record['twelve_hour'] = 1 + intval($record['twelve_hour']);
        }

        // one_day
        if(empty($record['one_day_ttl']) || $now - $record['one_day_ttl'] > 86400) {
            $record['one_day'] = 1;
            $record['one_day_ttl'] = $now;
        } else {
            $record['one_day'] = 1 + intval($record['one_day']);
        }

        return $record;
    }


    /**
     * 按IP组织访问信息
     */
    public function organizeByIp($service, $ip)
    {
        return $this->ip_record = $this->organize($this->getRecordByIp($service, $ip));
    }

    /**
     * 按account组织访问信息
     */
    public function organizeByAccount($service, $account)
    {
        return $this->account_record = $this->organize($this->getRecordByAccount($service, $account));
    }

    /**
     * 根据IP获取历史访问信息
     * @param $service
     * @param $ip
     * @return array
     */
    public function getRecordByIp($service, $ip)
    {
        if(empty($service) || !is_string($service) || empty($ip) || !is_string($ip)) {
            return [];
        }

        $ret = $this->getRedis()->hGetAll(self::IP_PREFIX . $service . ':' . $ip);
        //myprint($ret, true);
        if(!empty($ret)) {
            $this->need_set_ip_expire = false;
        }

        return $ret ?: [];
    }

    /**
     * 根据account获取历史访问信息
     * @param $service
     * @param $account
     * @return array
     */
    public function getRecordByAccount($service, $account)
    {
        if(empty($service) || !is_string($service) || empty($account) || !is_string($account)) {
            return [];
        }

        $ret = $this->getRedis()->hGetAll(self::ACCOUNT_PREFIX . $service . ':' . $account);
        if(!empty($ret)) {
            $this->need_set_account_expire = false;
        }
        return $ret ?: [];
    }


    /**
     * @var \artisan\cache\PHPredisDriver
     */
    private $redis;

    /**
     * @return \artisan\cache\PHPredisDriver
     */
    private function getRedis()
    {
        if(empty($this->redis)) {
            $this->redis = \artisan\cache::connect(config::get('access', 'redis'));
        }
        return $this->redis;
    }
}